﻿using System;
using System.Reflection;

namespace Pfz.Factoring
{
	/// <summary>
	/// A factory that results objects of type T that was created for the data-type TData.
	/// </summary>
	public sealed class Factory<T, TData>:
		IFactory<T>
	{
		private ConstructorInfo _constructor;
		internal Factory(ConstructorInfo constructor, Type baseDataType)
		{
			_constructor = constructor;
			BaseDataType = baseDataType;
		}

		/// <summary>
		/// Gets the BaseDataType of this factory. This may be different from DataType if the registered
		/// object supports working with sub-types of its base data type.
		/// </summary>
		public Type BaseDataType { get; private set; }

		/// <summary>
		/// Creates a new object of type T, prepared to deal with objects of type TData.
		/// </summary>
		public T Create()
		{
			var result = (T)_constructor.Invoke(null);

			var preferredDataType = result as IHasPreferredDataType;
			if (preferredDataType != null)
				preferredDataType.PreferredDataType = typeof(TData);

			return result;
		}

		Type IFactory.FactoryBaseType
		{
			get
			{
				return typeof(T);
			}
		}

		Type IFactory.DataType
		{
			get
			{
				return typeof(TData);
			}
		}

		object IFactory.Create()
		{
			return Create();
		}
	}
}
